package main

import (
	"bytes"
	"encoding/csv"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
	"sync"
)

type CsvDownload struct {
	baseDir        string
	csvfile        string
	downloadColumn int
	wg             sync.WaitGroup
	mutex          sync.Mutex
	handledFileMap sync.Map
}

func NewCsvDownload() *CsvDownload {
	return new(CsvDownload)
}

func (csvDownload *CsvDownload) SetBaseDir(baseDir string) *CsvDownload {
	csvDownload.baseDir = baseDir
	return csvDownload
}

func (csvDownload *CsvDownload) SetCsvFile(csvfile string) *CsvDownload {
	csvDownload.csvfile = csvfile
	return csvDownload
}

func (csvDownload *CsvDownload) SetDownloadColumn(downloadColumn int) *CsvDownload {
	csvDownload.downloadColumn = downloadColumn
	return csvDownload
}

func (csvDownload *CsvDownload) Download() {
	// todo: 改造成channel形式

	err := csvDownload.readcsvfile()
	if err != nil {
		fmt.Println("Error: ", err)
		return
	}
}

func (csvDownload *CsvDownload) readcsvfile() error {
	file, err := os.Open(csvDownload.csvfile)
	if err != nil {
		return err
	}
	defer file.Close()

	// 读取文件
	reader := csv.NewReader(file)
	i := 1
	csvDownload.wg = sync.WaitGroup{}
	for {
		recordArr, err := reader.Read()
		if err == io.EOF {
			break
		} else if err != nil {
			return err
		}

		// 获取内容
		imgUrl := recordArr[csvDownload.downloadColumn]
		if !isHttp(imgUrl) {
			continue
		} else {
			//fmt.Println(getImageName(imgUrl, i, ".png"))

			csvDownload.wg.Add(1)
			go func(imgUrl string, i int) {
				defer csvDownload.wg.Done()
				csvDownload.downloadPic(imgUrl, getImageName(imgUrl, i, ".png"))
			}(imgUrl, i)

			i++
		}
	}

	csvDownload.wg.Wait()
	return nil
}

// 下载图片
func (csvDownload *CsvDownload) downloadPic(url string, name string) {
	// 计时模块
	//start := time.Now()
	//defer func() {
	//	fmt.Println(time.Now().Sub(start).String())
	//}()

	// 下载失败的捕获并记录
	defer func() {
		if r := recover(); r != nil {
			fmt.Printf("下载失败; #原因#: %s, #url#: %s, #name#: %s \n", r, url, name)
		}
	}()


	// 判断是否已下载(原子性判断)
	csvDownload.mutex.Lock()
	flag, ok := csvDownload.handledFileMap.Load(url)
	if ok {
		csvDownload.mutex.Unlock()
		return
	} else {
		csvDownload.handledFileMap.Store(url, true)
	}
	csvDownload.mutex.Unlock()


	// 下载路径名
	name = csvDownload.baseDir + "/" + name

	// 检查图片是否重复
	flag, err := PathExists(name)
	if err != nil {
		fmt.Println("Error: ", err)
		return
	}
	if flag != false {
		return
	}

	// 下载图片
	resp, err := http.Get(url)
	if err != nil {
		fmt.Println("Error: ", err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("Error: ", err)
		return
	}
	out, err := os.Create(name)
	if err != nil {
		fmt.Println("Error: ", err)
		return
	}
	defer out.Close()
	io.Copy(out, bytes.NewReader(body))

	// 下载的名字
	fmt.Println(name)
}

/**
 * 检查是否http链接
 */
func isHttp(str string) bool {
	return strings.Contains(str, "http")
}

// 获取图片名字（如果url有，则取url里面的）
func getImageName(url string, i int, posfix string) string {
	name := strconv.Itoa(i)
	if strings.Contains(url, "cdn.weipaitang.com") || strings.Contains(url, "cdn.wptqc.com") {
		arr := strings.Split(url, "/")
		name = arr[4]
	}

	return name + posfix
}

func PathExists(path string) (bool, error) {
	_, err := os.Stat(path)
	if err == nil {
		return true, nil
	}
	if os.IsNotExist(err) {
		return false, nil
	}
	return false, err
}
